\section{Пустая функция}
\label{empty_func}

Простейшая функция из всех возможных, это функция, которая ничего не делает:

\lstinputlisting[caption=Код на \CCpp,style=customc]{patterns/00_empty/1.c}

Скомпилируем!

\subsection{x86}

Для x86 и MSVC и GCC делает одинаковый код:

\lstinputlisting[caption=\Optimizing GCC/MSVC (\assemblyOutput),style=customasmx86]{patterns/00_empty/1.s}

\myindex{x86!\Instructions!RET}
Тут только одна инструкция: \RET, которая возвращает управление в \glslink{caller}{вызывающую ф-цию}.

\subsection{ARM}

\lstinputlisting[caption=\OptimizingKeilVI (\ARMMode) ASM Output,style=customasmARM]{patterns/00_empty/1_Keil_ARM_O3.s}

Адрес возврата (\ac{RA}) в ARM не сохраняется в локальном стеке, а в регистре \ac{LR}.
Так что инструкция \INS{BX LR} делает переход по этому адресу, и это то же самое что и вернуть управление
в вызывающую ф-цию.

\subsection{MIPS}

Есть два способа называть регистры в мире MIPS. По номеру (от \$0 до \$31) или по псевдоимени (\$V0, \$A0, итд.).

Вывод на ассемблере в GCC показывает регистры по номерам:

\lstinputlisting[caption=\Optimizing GCC 4.4.5 (\assemblyOutput),style=customasmMIPS]{patterns/00_empty/MIPS.s}

\dots а \IDA --- по псевдоименам:

\lstinputlisting[caption=\Optimizing GCC 4.4.5 (IDA),style=customasmMIPS]{patterns/00_empty/MIPS_IDA.lst}

\myindex{MIPS!\Instructions!J}

Первая инструкция --- это инструкция перехода (J или JR),
которая возвращает управление в \glslink{caller}{вызывающую ф-цию}, переходя по адресу в регистре \$31 (или \$RA).

Это аналог регистра \ac{LR} в ARM.

Вторая инструкция это \ac{NOP}, которая ничего не делает.
Пока что мы можем её игнорировать.

\subsubsection{Еще кое-что об именах инструкций и регистров в MIPS}
Имена регистров и инструкций в мире MIPS традиционно пишутся в нижнем регистре.
Но мы будем использовать верхний регистр, потому что имена инструкций и регистров других
\ac{ISA} в этой книге так же в верхнем регистре.

\subsection{Пустые функции на практике}

Не смотря на то, что пустые функции бесполезны, они довольно часто встречаются в низкоуровневом коде.

Во-первых, популярны функции, выводящие информацию в отладочный лог, например:

\lstinputlisting[caption=Код на \CCpp,style=customc]{patterns/00_empty/dbg_print.c}

В не-отладочной сборке (например, ``release''), \TT{\_DEBUG} не определен, так что функция \TT{dbg\_print()},
не смотря на то, что будет продолжать вызываться в процессе исполнения, будет пустой.

Во-вторых, популярный способ защиты ПО это компиляция нескольких сборок: один для легальных покупателей,
второй --- демонстрационный.
Демонстрационная сборка может не иметь каких-то важных функций, например:

\lstinputlisting[caption=Код на \CCpp,style=customc]{patterns/00_empty/demo.c}

Функция \TT{save\_file()} может быть вызвана, когда пользователь кликает меню \TT{File->Save}.
Демо-версия может поставляться с отключенным пунктом меню, но даже если кракер разрешит этот пункт,
будет вызываться пустая функция, в которой полезного кода нет.

IDA маркирует такие функции именами вроде \TT{nullsub\_00}, \TT{nullsub\_01}, итд.

